package com.smart.wap.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjUtil;
import com.smart.common.cache.CacheService;
import com.smart.common.entities.constant.SocKetTips;
import com.smart.manager.member.entities.bodys.RMemberMaterialProps;
import com.smart.manager.member.entities.enums.CoinAccountEvent;
import com.smart.manager.member.entities.enums.EnergyAccountEvent;
import com.smart.manager.member.entities.enums.PropsKind;
import com.smart.manager.member.entities.models.*;
import com.smart.manager.member.entities.models.query.QMemberMaterialPig;
import com.smart.manager.member.entities.models.query.QMemberMaterialPigPlan;
import com.smart.manager.member.entities.models.query.QMemberMaterialProps;
import com.smart.manager.member.entities.views.MemberView;
import com.smart.manager.member.entities.views.query.QMemberView;
import com.smart.manager.member.repository.*;
import com.smart.manager.pop.entities.enums.BillKind;
import com.smart.manager.pop.entities.models.PopBasicDiamond;
import com.smart.manager.pop.entities.models.PopC2cAttend;
import com.smart.manager.pop.entities.models.PopC2cRecord;
import com.smart.manager.pop.entities.models.query.QPopBasicDiamond;
import com.smart.manager.pop.entities.models.query.QPopC2cAttend;
import com.smart.manager.pop.entities.models.query.QPopC2cRecord;
import com.smart.manager.pop.repository.DisInviterRepository;
import com.smart.manager.product.entities.enums.PigstyKind;
import com.smart.manager.product.entities.enums.ProfileStatus;
import com.smart.manager.product.entities.enums.ServeTask;
import com.smart.manager.product.entities.models.*;
import com.smart.manager.product.entities.models.query.QPigGoods;
import com.smart.manager.product.entities.models.query.QPigLevel;
import com.smart.manager.product.entities.models.query.QPropsServe;
import com.smart.manager.product.entities.models.query.QPropsSnacks;
import com.smart.manager.product.entities.views.PropsComboView;
import com.smart.manager.product.entities.views.PropsProfileView;
import com.smart.manager.product.entities.views.query.QPropsComboView;
import com.smart.manager.product.entities.views.query.QPropsProfileView;
import com.smart.manager.product.repository.*;
import com.smart.manager.work.repository.PigOrderRepository;
import com.smart.service.remind.RemindService;
import com.smart.service.socket.WebSocket;
import com.smart.wap.bodys.ShopBody;
import com.smart.wap.bodys.ShopResult;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 商店操作
 *
 * @author leo
 * @date 2023/09/21
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class ShopService {

    private final MemberAccountRepository memberAccountRepository;
    private final MemberMaterialPropsRepository memberMaterialPropsRepository;
    private final PigGoodsRepository pigGoodsRepository;
    private final PigOrderRepository pigOrderRepository;
    private final PropsSnacksRepository propsSnacksRepository;
    private final PropsServeRepository propsServeRepository;
    private final PropsComboRepository propsComboRepository;
    private final MemberMaterialPigUseRepository memberMaterialPigUseRepository;
    private final MemberFriendRepository memberFriendRepository;
    private final DisInviterRepository disInviterRepository;
    private final BasicCameraDetailRepository basicCameraDetailRepository;
    private final RemindService remindService;
    private final PigService pigService;
    private final WebSocket webSocket;
    private final CacheService cacheService;

    private final BatchService batchService;
    private final MemberMaterialPigRepository materialPigRepository;

    /**
     * 获取所有上架的猪仔
     *
     * @param id 用户
     * @return {@link List}<{@link PigGoods}>
     */
    public List<PigGoods> getGoodsList(Long id) {


        return pigGoodsRepository.getList();
    }


    /**
     * 获取邀请活动详情
     *
     * @param id id
     * @return {@link PopC2cAttend}
     */
    public List<MemberView> getActivity(Long id) {
        Optional<PopC2cAttend> attend = new QPopC2cAttend()
                .member.id.eq(id).activity.id.eq(1721862061069029376L)
                .setMaxRows(1).findOneOrEmpty();
        if (attend.isEmpty()) {
            return null;
        }
        PopC2cAttend x = attend.get();
        List<PopC2cRecord> records = new QPopC2cRecord().activity.id.eq(x.getActivity().getId()).actor.eq(x.getMember()).prizeAttr.eq(false).order().id.asc().findList();
        return records.stream().map(PopC2cRecord::getActor).collect(Collectors.toList());
    }


    /**
     * 获取所有上架的零食
     *
     * @param id 用户
     * @return {@link List}<{@link PropsSnacks}>
     */
    public List<PropsSnacks> getSnacksList(Long id) {
        return propsSnacksRepository.getList();
    }

    /**
     * 获取所有上架的服务
     *
     * @param id 用户
     * @return {@link List}<{@link PropsServe}>
     */
    public List<PropsServe> getServeList(Long id) {
        return propsServeRepository.getList();
    }

    /**
     * 根据猪猪等级获取所有上架的套餐
     *
     * @param id 用户
     * @return {@link List}<{@link PropsCombo}>
     */
    public List<PropsCombo> getComboList(Long id, String code) {
        Optional<MemberMaterialPig> empty = new QMemberMaterialPig().code.eq(code).setMaxRows(1).findOneOrEmpty();
        if (empty.isPresent()) {
            return propsComboRepository.getList(empty.get().getPigLevel().getDay());
        }
        throw new RuntimeException("猪猪不存在!");
    }

    /**
     * 获取所有上架的套餐
     *
     * @return {@link List}<{@link PropsCombo}>
     */
    public ShopResult.Combo getAllList(Boolean isOrganic) {
        ShopResult.Combo combo1 = cacheService.getShopResultCache().get("TC001");
        if (ObjUtil.isNull(combo1)) {
            PropsCombo oneList = propsComboRepository.getOne(isOrganic);
            Assert.isFalse(ObjUtil.isNull(oneList), "暂无套餐数据!");
            List<PropsCombo> allList = propsComboRepository.getAllList(isOrganic);
            ShopResult.Combo combo = BeanUtil.copyProperties(oneList, ShopResult.Combo.class);
            if (combo.getDiscountPrice().doubleValue() != 0) {
                combo.setTotalPrice(NumberUtil.round(NumberUtil.mul(oneList.getPrice(), oneList.getDiscountPrice()), 0));
            } else {
                combo.setTotalPrice(new BigDecimal(combo.getPrice()));
            }
            List<PropsProfileView> profiles = new QPropsProfileView().findList();
            Map<String, PropsProfileView> viewMap = profiles.stream()
                    .collect(Collectors.toMap(PropsProfileView::getCode, Function.identity(), (existing, replacement) -> existing));
            List<ShopResult.ComboList> collect = allList.stream().map(x -> {
                ShopResult.ComboList comboList = BeanUtil.copyProperties(x, ShopResult.ComboList.class);
                if (ObjUtil.isNotNull(x.getMeat()) && x.getMeat().size() > 0) {
                    List<ShopResult.Profile> profiles1 = new ArrayList<>();
                    x.getMeat().forEach(c -> {
                        PropsProfileView view = viewMap.get(c);
                        if (ObjUtil.isNotNull(view)) {
                            profiles1.add(BeanUtil.copyProperties(view, ShopResult.Profile.class));
                        }
                    });
                    comboList.setMeats(profiles1);
                }
                return comboList;
            }).collect(Collectors.toList());
            combo.setComboLists(collect);
            cacheService.getShopResultCache().put("TC001", combo);
            combo1 = combo;
        }
        return combo1;
    }

    /**
     * 购买猪的操作
     *
     * @param memberId 会员id
     * @param body     猪仔body
     */
//    @Transactional(rollbackFor = Exception.class)
    public MemberMaterialPig buyPig(Long memberId, ShopBody.EditBody body) {
        MemberProfileAccount account = memberAccountRepository.getAccount(memberId);
        MemberView memberView = new MemberView().setId(account.getMember().getId());
        Optional<PigGoods> oneOrEmpty = new QPigGoods().code.eq(body.getCode()).status.eq(ProfileStatus.ON).setMaxRows(1).findOneOrEmpty();
        Assert.isFalse(oneOrEmpty.isEmpty(), "猪猪不存在 或者猪猪已下架");
        PigGoods pigGoods = oneOrEmpty.get();
        log.warn("猪仔价格 === {}", pigGoods);
        //猪仔金额 + 备用金 + 疾病险 + 养猪险
        Integer collect = pigGoods.getPrice() + pigGoods.getReserveFund();
        StringBuilder msg = new StringBuilder("购买猪仔");
        //如果是兑换的话
        if (!body.getIsFull()&&body.getIsMedal()) {
                MemberMaterialProps props = new QMemberMaterialProps().code.eq(body.getMedalCode()).kind.eq(PropsKind.L5).setMaxRows(1).findOne();
                if (!ObjUtil.isEmpty(props)) {
                    PopBasicDiamond diamond = new QPopBasicDiamond().code.eq(body.getMedalCode()).setMaxRows(1).findOne();
                    collect = collect - diamond.getPrice();
                    msg.append("_助力抵扣卷");
                    log.warn("_助力抵扣卷");
                    pigService.deduct(props, 1);
                }
        } else {
            collect = pigGoods.getFullPrice();
        }
        Assert.isFalse(account.getCoinBalance() < collect, "余额不足");
        //生成流水
        log.warn("购买猪猪 实际扣减 = {}",collect);
        memberAccountRepository.saveEvent(account.getMember().getId(), CoinAccountEvent.BUYPIG, collect, msg.toString());
        //判断是否是赠送
        if (ObjUtil.isNotNull(body.getFriends())) {
            //判断是否是好友
            Optional<MemberRelationFriend> friends = memberFriendRepository.isFriends(memberId, body.getFriends());
            Assert.isFalse(friends.isEmpty(), "你们还是不好友请添加好友后操作");
            memberView = new QMemberView().id.eq(body.getFriends()).findOne();
            //提醒好友赠送
            log.warn("提醒好友赠送");
            //站内消息
            remindService.sendGiveMsg(memberView.getId());
            //socket消息
            webSocket.sendOneMessage(memberView.getId(), SocKetTips.givePigSucceed);
            //站内消息
            remindService.sendAddGiveMsg(memberId, memberView);
        }
        //生成猪仔 _ 跟随套餐 _ 改名卡  _ 鸡蛋 _ 喂养端工单 _ 客服工单
        MemberMaterialPig pig = materialPigRepository.addPig(pigGoods, body.getIsFull(), memberView,0);
        //计算提成
        disInviterRepository.buyPig(account.getMember().getPhoneNumber(), BillKind.RAISE, BigDecimal.valueOf(pigGoods.getPrice()));
        return pig;
    }




//    public ShopResult.Rem verifyExchange(ShopBody.ExchangeBody body, Long memberId) {
//        Optional<PigGoods> oneOrEmpty = new QPigGoods().code.eq(body.getCode()).status.eq(ProfileStatus.ON).setMaxRows(1).findOneOrEmpty();
//        Assert.isFalse(oneOrEmpty.isEmpty(), "猪猪不存在 或者猪猪已下架");
//        PigGoods pigGoods = oneOrEmpty.get();
//        MemberView view = new QMemberView().id.eq(memberId).setMaxRows(1).findOne();
//        return isExchange(body.getRedeemCodes(), pigGoods, view, false);
//    }

//    public ShopResult.Rem isExchange(String cdk, PigGoods goods, MemberView view, Boolean isUse) {
//        PopDisExchange exchange = new QPopDisExchange().redeemCodes.eq(cdk).setMaxRows(1).findOne();
//        Assert.isFalse(ObjUtil.isNull(exchange), "兑换码不正确!");
//        Assert.isFalse(exchange.getState().equals(CDKState.ALREADY), "兑换码已被使用!");
//        Assert.isTrue(goods.getIsExchange(), "当前猪猪 不支持兑换");
//        ShopResult.Rem rem = new ShopResult.Rem();
//        switch (exchange.getKind()) {
//            case PIG:
//                Integer amount = goods.getReserveFund() + goods.getInsurance() + goods.getAccident();
//                rem.setTitle(exchange.getKind().getLabel() + "卷 仅需支付猪仔备用金").setAmount(amount).setKind(exchange.getKind());
//                if (isUse) {
//                    exchange.setState(CDKState.ALREADY).setUseMember(view).setUseTime(LocalDateTime.now()).update();
//                }
//                return rem;
//            case DISCOUNT:
//                Integer amount1 = goods.getPrice() + goods.getReserveFund() + goods.getInsurance() + goods.getAccident();
//                BigDecimal mul = NumberUtil.mul(amount1, exchange.getProportion());
//                rem.setTitle(exchange.getKind().getLabel() + "卷" + exchange.getProportion() + "折").setAmount(mul.intValue()).setKind(exchange.getKind());
//                if (isUse) {
//                    exchange.setState(CDKState.ALREADY).setUseMember(view).setUseTime(LocalDateTime.now()).update();
//                }
//                return rem;
//            default:
//                Assert.isTrue(false, "当前类型兑换卷暂不支持使用!");
//                return null;
//        }
//    }

    /**
     * 兑换零食
     *
     * @param memberId 会员
     * @param body     body
     */
    public Map<String, Object> redeemSnacks(Long memberId, ShopBody.GoodsBody body) {
        MemberProfileAccount account = memberAccountRepository.getAccount(memberId);
        //零食兑换
        Optional<PropsSnacks> snacks = new QPropsSnacks().code.eq(body.getCode()).setMaxRows(1).findOneOrEmpty();
        Assert.isFalse(snacks.isEmpty(), "零食不存在或者已下架!");
        int cnt = snacks.get().getEnergy() * body.getNumber();
        Assert.isTrue(account.getPowerBalance() >= cnt, "您的能量不足!");
        memberAccountRepository.savePowerEvent(memberId, EnergyAccountEvent.EXCHANGE, cnt, "兑换了");
        //把零食添加到背包
        memberMaterialPropsRepository.add(new RMemberMaterialProps.EditBody().setIcon(snacks.get().getIcon()).setName(snacks.get().getName()).setMember(account.getMember()).setNumber(body.getNumber()).setKind(PropsKind.L1).setCode(body.getCode()));
        return Map.of("code", snacks.get().getCode(), "number", body.getNumber());
    }

    /**
     * 购买服务
     *
     * @param memberId 会员
     * @param body     body
     */
    public String purchaseServices(Long memberId, ShopBody.ServeBody body) {
        MemberProfileAccount account = memberAccountRepository.getAccount(memberId);
        Optional<MemberMaterialPig> pig = new QMemberMaterialPig().code.eq(body.getCodePig()).setMaxRows(1).findOneOrEmpty();
        Assert.isFalse(pig.isEmpty(), "未找到当前猪仔!");
        Assert.isTrue(pig.get().getMember().getId().equals(memberId) || ObjUtil.isNotNull(pig.get().getCloseMember()) && pig.get().getCloseMember().getId().equals(memberId), "您不能操作别人的猪猪");
        Assert.isTrue(pig.get().getPigsty().getKind().equals(PigstyKind.ALONE), "您的猪猪是" + PigstyKind.COMMON.getLabel() + "不支持服务!");
        Optional<PropsServe> view1 = new QPropsServe().code.eq(body.getCode()).setMaxRows(1).findOneOrEmpty();
        Assert.isFalse(view1.isEmpty(), "服务不存在或者已下架!");
        Assert.isTrue(account.getCoinBalance() >= view1.get().getPrice(), "您的余额不足!");
        memberAccountRepository.saveEvent(account.getMember().getId(), CoinAccountEvent.SHOPOUT, view1.get().getPrice(), "购买服务");
        PropsServe propsServe = view1.get();
        PropsKind kind = PropsKind.L3;
        if (propsServe.getTask().equals(ServeTask.RECHRISTEN)) {
            kind = PropsKind.L2;
        }
        memberMaterialPropsRepository.add(new RMemberMaterialProps.EditBody().setName(view1.get().getName()).setIcon(view1.get().getIcon()).setCode(view1.get().getCode()).setNumber(1).setMember(account.getMember()).setKind(kind).setDurable(0));
        disInviterRepository.buyPig(account.getMember().getPhoneNumber(), BillKind.CONSUME, new BigDecimal(view1.get().getPrice()));
        return view1.get().getCode();
    }


    /**
     * 给猪仔购买套餐
     *
     * @param memberId 用户
     * @param body     body
     */
    public Map<String, Object> buyPutPig(Long memberId, ShopBody.GoodsPigBody body) {
        MemberProfileAccount account = memberAccountRepository.getAccount(memberId);
        Optional<MemberMaterialPig> orEmpty = new QMemberMaterialPig().code.eq(body.getCodePig()).findOneOrEmpty();
        Assert.isFalse(orEmpty.isEmpty(), "猪猪不存在!");
        MemberMaterialPig materialPig = orEmpty.get();
        Assert.isTrue(orEmpty.get().getMember().getId().equals(memberId) || orEmpty.get().getCloseMember().getId().equals(memberId), "您不能操作别人的猪猪");
        //验证是否超过最大等级 并且返回当前最大计划
        List<MemberMaterialPigPlan> pigPlans = verification(materialPig, body.getNumber());
        //判断当前套餐是否 适用于当前猪仔
        Optional<PropsComboView> view = new QPropsComboView().code.eq(body.getCode()).setMaxRows(1).findOneOrEmpty();
        Assert.isFalse(view.isEmpty(), "当前套餐不适用您的猪猪!");
        PropsComboView comboView = view.get();
        Assert.isTrue(materialPig.getPigsty().getIsOrganic().equals(comboView.getIsOrganic()), "当前套餐不适用您的猪猪!");
        Integer pas = comboView.getPrice();
        if (comboView.getDiscountPrice().doubleValue() != 0) {
            BigDecimal round = NumberUtil.round(NumberUtil.mul(comboView.getPrice(), comboView.getDiscountPrice()), 0);
            pas = round.intValue();
        }
        Assert.isTrue(account.getCoinBalance() >= pas, "您的余额不足!");
        memberAccountRepository.saveEvent(account.getMember().getId(), CoinAccountEvent.SHOPOUT, view.get().getPrice(), "购买套餐");
        //购买成功后添加到 猪猪计划表中
        //查询当前最大日程
        batchService.addListPlan(pigPlans, comboView, account.getMember().getId(), materialPig.getId(), body.getNumber());

        return Map.of("code", body.getCode(), "number", body.getNumber());
    }


    /**
     * 验证购买的天数是否超过猪仔升级的 最大天数
     *
     * @param pig 验证的猪仔
     * @param day 添加的天数
     * @return {@link List}<{@link MemberMaterialPigPlan}>
     */
    public List<MemberMaterialPigPlan> verification(MemberMaterialPig pig, Integer day) {
        //获取一个品种
        Optional<PigLevel> pigLevel = new QPigLevel().breed.eq(pig.getBreed()).day.eq(pig.getPigLevel().getDay()).kind.eq(pig.getPigsty().getKind()).setMaxRows(1).findOneOrEmpty();
        Assert.isFalse(pigLevel.isEmpty(), "");
        //acb 是当前这只猪 距离下一个阶段需要的的天数
        List<PigLevel> acb = new QPigLevel().breed.code.eq("ACB").kind.eq(pig.getPigsty().getKind()).stage.eq(pigLevel.get().getStage()).day.gt(pig.getPigLevel().getDay()).findList();
        List<MemberMaterialPigPlan> plans = new QMemberMaterialPigPlan().pigId.id.eq(pig.getId()).order().eatDate.desc().findList();
        //通过当前时间来计算
        LocalDate daysAfterPurchase = LocalDate.now();
        if (CollUtil.isNotEmpty(plans)) {
            //通过计划表开始计算
            MemberMaterialPigPlan pigPlan = plans.get(0);
            daysAfterPurchase = pigPlan.getEatDate().plusDays(3);
        }
        //计算出 升级的最后一天是几号  //判断有这次购买有没有超过 总天数
        LocalDate daysLeftToGrow = LocalDate.now().plusDays(acb.size());
        long daysBetween = ChronoUnit.DAYS.between(daysLeftToGrow, daysAfterPurchase);
        String msg = daysBetween == 0 ? "马上" : String.valueOf(daysBetween);
        Assert.isFalse(daysLeftToGrow.isAfter(daysAfterPurchase), "您的猪猪" + msg + "后升级");
        return plans;
    }
}
